/*
 * Copyright (C) 2008 Alessandro Sivieri <alessandro.sivieri@chimera-bellerofonte.eu>.
 *
 *  This file is part of Daex.
 *
 *  Daex is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  Foobar is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with Foobar.  If not, see <http://www.gnu.org/licenses/>.
 */
package eu.chimera_bellerofonte.tesi.ui.models;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;

import javax.swing.AbstractListModel;

import eu.chimera_bellerofonte.tesi.datatypes.Song;
import eu.chimera_bellerofonte.tesi.encoding.Encoder;


/**
 * <p>Classe di definizione della ListModel basata su ArrayList,
 * sulla falsariga della DefaultListModel by Sun; tuttavia
 * aggiunge un metodo di sorting ed implementa solo i metodi
 * effettivamente utilizzati. Viene dichiarata come astratta
 * poiche' sono necessarie diverse implementazioni a seconda
 * della tecnologia impiegata per la costruzione della gui.</p>
 * <p>Questa lista assicura di aggiornare la parte visiva nelle
 * chiamate che modifichino la lista interna di visualizzazione;
 * aggiunge alcuni metodi di refresh (call(), refresh()) che devono
 * essere invocati in caso di cambiamenti nella base di dati (questa
 * e' infatti unica ma la parte grafica ha bisogno di sapere eventuali
 * modifiche da visualizzare in sincrono).</p>
 * 
 * @author Sivieri Alessandro
 * @author Vitucci Nicola
 * @version 24/mag/07
 */
public abstract class SortedListModel extends AbstractListModel
{
	static final long serialVersionUID = 1L;
	private ArrayList<Song> objects=null;
	private Encoder encoder=null;

	/**
	 * Costruttore; setta gli attributi di classe con i
	 * valori specificati.
	 * 
	 * @param encoder l'encoder associato al modello
	 */
	protected SortedListModel(Encoder encoder)
	{
		this.encoder=encoder;
		objects=new ArrayList<Song>(0);
	}

	/**
	 * @see javax.swing.ListModel#getElementAt(int)
	 */
	public Song getElementAt(int index)
	{

		return objects.get(index);
	}

	/**
	 * @see javax.swing.ListModel#getSize()
	 */
	public int getSize()
	{
		return objects.size();
	}
	
	/**
	 * @see java.util.ArrayList#toArray()
	 */
	public Object[] toArray()
	{
		return objects.toArray();
	}

	/**
	 * @see java.util.ArrayList#indexOf(Object)
	 */
	public int indexOf(Object e)
	{
		return objects.indexOf(e);
	}
	
	/**
	 * @see java.util.ArrayList#add(Object)
	 */
	public void addElement(Song o)
	{
		if(check(o))
		{
			int index=objects.size();
			objects.add(o);
			fireIntervalAdded(this, index, index);
		}
	}
	
	/**
	 * @see java.util.ArrayList#remove(int)
	 */
	public void removeElementAt(int i)
	{
		objects.remove(i);
		fireIntervalRemoved(this, i, i);
	}
	
	/**
	 * @see java.util.ArrayList#remove(Object)
	 */
	public void removeElement(Object o)
	{
		int i=objects.indexOf(o);
		if(i!=-1)
		{
			objects.remove(o);
			fireIntervalRemoved(this, i, i);
		}
	}
	
	public void removeElements(Object[] objs)
	{
		for(Object o: objs)
			objects.remove(o);
		fireContentsChanged(this, 0, objects.size());
	}
	
	/**
	 * Metodo per il sorting della lista visualizzata a schermo;
	 * viene agganciato un comparatore per Song come parametro,
	 * trattandosi di un sistema di ordinamento non necessariamente
	 * corrispondente a quello implementato nella versione standard
	 * della classe.
	 * 
	 * @see eu.chimera_bellerofonte.tesi.datatypes.Song
	 * @see java.util.Collections#sort(java.util.List, Comparator)
	 */
	public void sort()
	{
		Collections.sort(objects, new Comparator<Song>()
		{

			public int compare(Song o1, Song o2)
			{
				return new Integer(o1.getStartChapter()).compareTo(new Integer(o2.getStartChapter()));
			}
			
		});
		fireContentsChanged(this, 0, objects.size()-1);
	}
	
	/**
	 * Verifica se esiste gia' nella lista degli oggetti un elemento
	 * Song con il medesimo titolo.
	 * 
	 * @param s la canzone il cui titolo si chiede se esiste o meno
	 * @return true se non esiste, false altrimenti
	 */
	public boolean check(Song s)
	{
		for(Song ss: objects)
		{
			if(ss.getTitle().equals(s.getTitle()))
			{
				return false;
			}
		}
		return true;
	}
	
	/**
	 * @see java.util.ArrayList#set(int, Object)
	 */
	public void set(int index, Song newSong)
	{
		objects.set(index, newSong);
	}
	
	/**
	 * Metodo per sostituire un elemento gia' presente nella lista
	 * ma di cui sia cambiato il titolo.
	 * 
	 * @param oldTitle il vecchio titolo dell'elemento
	 * @param newSong il nuovo oggetto da inserire nella lista
	 */
	public void set(String oldTitle, Song newSong)
	{
		int i;
		for(i=0; i<objects.size(); i++)
		{
			if(objects.get(i).getTitle().equals(oldTitle))
			{
				objects.set(i, newSong);
			}
		}
		fireContentsChanged(this, i, i);
	}
	
	/**
	 * Metodo per avvertire la lista di un cambiamento nella
	 * base di dati sottostante.
	 * 
	 * @param oldTitle il vecchio titolo dell'oggetto cui e' cambiato
	 */
	public void call(String oldTitle)
	{
		for(int i=0; i<objects.size(); i++)
		{
			if(objects.get(i).getTitle().equals(oldTitle))
			{
				fireContentsChanged(this, i, i);
			}
		}		
	}
	
	/**
	 * Metodo per il refresh completo della lista.
	 */
	public void refresh()
	{
		eraseCouples();
		fireContentsChanged(this, 0, getSize()-1);
	}

	/**
	 * Metodo per la pulitura di tutti gli elementi della
	 * lista.
	 */
	public void clear()
	{
		int i=objects.size();
		objects.clear();
		fireIntervalRemoved(this, 0, i);
	}
	
	/**
	 * Metodo per avere tutte le canzoni agganciate a questo modello
	 * di encoding.
	 * 
	 * @return un arraylist di oggetti Song
	 */
	public ArrayList<Song> getElements()
	{
		return objects;
	}
	
	private void eraseCouples()
	{
		boolean ready=false, skip=false;
		
		while(!ready)
		{
			ready=true;
			for(int i=0; i<objects.size() && !skip; i++)
			{
				for(int j=i+1; j<objects.size() && !skip; j++)
				{
					if(objects.get(i).getTitle().equals(objects.get(j).getTitle()))
					{
						ready=false;
						skip=true;
						objects.remove(j);
					}
				}
			}
		}
	}
	
	/**
	 * Questo metodo ritorna il valore attuale di encoder.
	 * 
	 * @return il valore attuale di encoder
	 */
	public Encoder getEncoder()
	{
		return encoder;
	}

	/**
	 * @see java.lang.Object#toString()
	 */
	@Override
	public String toString()
	{
		return encoder.getEncoderTitle();
	}
	
}